<?php
/**
 * alltosun.com wxsdk.php
 * ============================================================================
 * 版权所有 (C) 2009-2013 北京互动阳光科技有限公司，并保留所有权利。
 * 网站地址: http://www.alltosun.com
 * ----------------------------------------------------------------------------
 * 许可声明：这是一个开源程序，未经许可不得将本软件的整体或任何部分用于商业用途及再发布。
 * ============================================================================
 * $Author: 王德康 (wangdk@alltosun.com) $
 * $Date: 2015-1-21 上午10:22:49 $
 * $Id$
 *
 *
 */
/*
两张标分别用来缓存 token 和  ticket

CREATE TABLE IF NOT EXISTS `weixin_token` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`token` varchar(512) NOT NULL DEFAULT '',
`expire_time` datetime NOT NULL,
`add_time` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


CREATE TABLE IF NOT EXISTS `weixin_ticket` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `jsapi_ticket` varchar(512) NOT NULL DEFAULT '',
  `expire_time` datetime NOT NULL,
  `add_time` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

*/

class wxsdk
{
    // 微信公众号ID
    private static $appId;

    // 微信公众号secret
    private static $appSecret;

    // 错误数组
    private static $errorArr;

    /**
     * 数据签名
     * @return multitype:string NULL number
     */
    public static function getSignPackage($url = '') {
        $weixin_config = Config::get('openapi');

        if ($weixin_config) {
            self::$appId     = $weixin_config['weixin'][0];
            self::$appSecret = $weixin_config['weixin'][1];
        }

        // 临时通行证
        $jsapiTicket = self::getJsApiTicket();

        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        if (!$url) $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $timestamp = time();
        $nonceStr = self::createNonceStr();

        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";

        $signature = sha1($string);

        $signPackage = array(
                "appId"     => self::$appId,
                "nonceStr"  => $nonceStr,
                "timestamp" => $timestamp,
                "url"       => $url,
                "signature" => $signature,
                "rawString" => $string
        );
        return $signPackage;
    }

    /**
     * 生成随机签名字符串
     * @param unknown_type $length
     * @return string
     */
    private static function createNonceStr($length = 16) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }


    /**
     * 获取公众账号的token(数据库缓存)
     * @return $token
     */
    private static function getJsApiTicket() {

        $ticket = '';

        $ticket_Info = _model('weixin_ticket')->read(array(1=>1));

        if (!$ticket_Info) {
            $ticket = self::updateTicket('create', 0);
            return $ticket;
        }

        if (strtotime($ticket_Info['expire_time']) < time()) {
            $ticket = self::updateTicket('update', $ticket_Info['id']);
            return $ticket;
        }

        return $ticket_Info['jsapi_ticket'];
    }

    /**
     * 获取公众账号的token
     * @return unknown
     */
    private static function getAccessToken() {

        $token_Info = _model('weixin_token')->read(array(1=>1));

        if (!$token_Info) {
            $access_token = self::updateAccessToken('create', 0);
            return $access_token;
        }

        if (strtotime($token_Info['expire_time']) < time()) {
            $access_token = self::updateAccessToken('update', $token_Info['id']);
            return $access_token;
        }

        return $token_Info['token'];
      }

      /**
       * 更新jsTicket 临时凭证
       * @param unknown_type $action
       * @param unknown_type $id
       * @return mixed|boolean
       */
      private static function updateTicket($action = 'create', $id)
      {
          $acccess_token = self::getAccessToken();

          $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token={$acccess_token}";
          $res = json_decode(self::httpGet($url), true);

          if (isset($res['errmsg']) && $res['errmsg'] == 'ok') {
              $data['jsapi_ticket'] = $res['ticket'];
              $data['expire_time']  = date('Y-m-d H:i:s', time() + $res['expires_in']);

              if($action == 'create') {
                  _model('weixin_ticket')->create($data);
              } else if ($action == 'update') {
                  _model('weixin_ticket')->update($id, $data);
              }

              return $res['ticket'];
          }
          // 保存错误日志
          self::$errorArr['ticket'] = $res['errmsg'];
          return false;
      }

      /**
       * 更新token
       * @param unknown_type $action create | update
       * @param unknown_type $id  更新Id
       * @return mixed|boolean
       */
      private static function updateAccessToken($action = 'create', $id)
      {
          $weixin_config = Config::get('openapi');

          if ($weixin_config) {
              self::$appId     = $weixin_config['weixin'][0];
              self::$appSecret = $weixin_config['weixin'][1];
          }

          $appId     = self::$appId;
          $appSecret = self::$appSecret;

          $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appId}&secret={$appSecret}";
          $res = json_decode(self::httpGet($url), true);

          if (!isset($res['errcode'])) {
              $data['token']       = $res['access_token'];
              $data['expire_time'] = date('Y-m-d H:i:s', time() + $res['expires_in']);

              if ($action == 'create') {
                  _model('weixin_token')->create($data);
              } else if ($action == 'update') {
                  _model('weixin_token')->update($id, $data);
              }

              return $res['access_token'];
          }

          // 保存错误日志
          self::$errorArr['token'] = $res['errmsg'];
          return false;
      }

    /**
     * Curl GET 请求
     * @param unknown_type $url
     * @return mixed
     */
    private static function httpGet($url)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 500);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_URL, $url);

        $res = curl_exec($curl);
        curl_close($curl);

        return $res;
    }
}
?>